package com.sql.db;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
/**
 * sql拼接代码
 * 一个完整的sql语句可以有多个sqlHandle拼接而成
 * sqlHandle分sql语句 与 sql值，在sql语句中值由？
 * 替代在最后运行是值将依此赋值给hibernate
 * @author 梁前武 
 * www.apkplug.com
 */
public class sqlHandle {
	public String strSql="%s";
	public Object fsql="";
	public String type="";
	public Object[] v=null;
	public List<sqlHandle> list=null;
	public sqlHandle(String strSql,Object fsql,String type,Object[] v){
		this.strSql=strSql;
		this.fsql=fsql;
		this.type=type;
		this.v=v;
	}
	public sqlHandle(Object fsql,String type,Object[] v){
		this.fsql=fsql;
		this.type=type;
		this.v=v;
	}
	public sqlHandle(){
	}
	public  SQLQuery handle(Session session){
		//拼接本sqlHandle sql字符串
		String sql=addWhereSql(strSql,fsql,type);
		for (int i=0;i<list.size();i++) {
			//依此拼接子sqlHandle
			sqlHandle sqlHandle = (sqlHandle) list.get(i);
			sql+=addWhereSql(sqlHandle.strSql,sqlHandle.fsql,sqlHandle.type);
		}
		System.out.println(sql);
		SQLQuery query=session.createSQLQuery(sql);
		//赋值
		setV(query,0);
		return query;
	}
	/**
	 * 将sql中？代替的值依此赋值给hibernate
	 * @param q
	 * @param i  传递值索引位置
	 * @return
	 */
	public int  setV(SQLQuery q,int i){
		if(v!=null)
		for(int j=0;j<v.length;j++){
			if(v[j]!=null){
				//System.out.println("添加参数");
				setV(q,i,v[j]);
				i++;
			}
		}
		if(fsql!=null&&fsql instanceof sqlHandle)
			i=((sqlHandle)fsql).setV(q, i);
		if(list!=null)
		for (int j=0;j<list.size();j++) {
			sqlHandle sqlHandle = (sqlHandle) list.get(j);
			i=sqlHandle.setV(q, i);
		}
		return i;
	}
	/**
	 * 将sql中？代替的值依此赋值给hibernate
	 * @param q
	 * @param i   值索引位置
	 * @param v   值
	 */
	public  void setV(SQLQuery q,int i,Object v){
		if(v instanceof String){
			q.setString(i, (String)v);
		}else if(v instanceof Integer){
			q.setInteger(i, (Integer)v);
		}else if(v instanceof Float){
			q.setFloat(i, (Float)v);
		}else if(v instanceof Double){
			q.setDouble(i, (Double)v);
		}else if(v instanceof Date){
			q.setDate(i, (Date)v);
		}else if(v instanceof java.sql.Date){
			q.setDate(i, (Date)v);
		}else if(v instanceof Boolean){
			q.setBoolean(i, (Boolean)v);
		}else if(v instanceof byte[]){
			q.setBinary(i, (byte[])v);
		}else if(v instanceof Byte){
			q.setByte(i, (Byte)v);
		}else if(v instanceof Calendar){
			q.setCalendar(i, (Calendar)v);
		}
	}
	
	/**
	 * 拼接sql字符串
	 * @param strSql 连接字符串 如 in(%s)
	 * @param sqlOne 实体字符串 如 select * user  可以是字符串也可以是sqlHandle
	 * @param type   连接类型   如 and,or
	 * @return 返回 如 and in(select * user)
	 */
	private static String addWhereSql(String strSql,Object sqlOne,String type){
		return  " "+type+" "+String.format(strSql, sqlOne)+" ";	
	}
	/**
	 * 添加多个sql参数值
	 * @param fsql  sql语句段   如 name=?
	 * @param type  sql连接类型  如 and
	 * @param v                 Object[]{"liming"} 如无值便为null
	 * @return
	 */
	public  sqlHandle AddMore(Object fsql,String type,Object[] v){
		if (list==null)
			list=new ArrayList<sqlHandle>();
		sqlHandle sql=new sqlHandle(fsql,type,v);
		list.add(sql);
		return this;
	}
	/**
	 * 添加0-1个sql参数
	 * @param fsql    sql语句段   如 name=?
	 * @param type    sql连接类型  如 and
	 * @param v       "liming" 如无值便为null
	 * @return
	 */
	public  sqlHandle Add(Object fsql,String type,Object v){
		AddMore( fsql, type,new Object[]{v});
		return this;
	}
	/**
	 * 添加多个sql参数值
	 * 多一共 strSql字符 有时我们需要 in(sql...) 这种情况。
	 * 我们可以通过设置 strSql=in(%s) fsql=sql... 这种形式来实现
	 * strSql默认为"%s"
	 * @param strSql  替代副
	 * @param fsql
	 * @param type
	 * @param v
	 * @return
	 */
	public  sqlHandle AddMoreAndRep(String strSql,Object fsql,String type,Object[] v){
		if (list==null)
			list=new ArrayList<sqlHandle>();
		sqlHandle sql=new sqlHandle(strSql,fsql,type,v);
		list.add(sql);
		return this;
	}
	/**
	 * 添加多个sql参数值
	 * 多一共 strSql字符 有时我们需要 in(sql...) 这种情况。
	 * 我们可以通过设置 strSql=in(%s) fsql=sql... 这种形式来实现
	 * strSql默认为"%s"
	 * @param strSql
	 * @param fsql
	 * @param type
	 * @param v
	 * @return
	 */
	public  sqlHandle AddAndRep(String strSql,Object fsql,String type,Object v){
		AddMoreAndRep(strSql, fsql, type,new Object[]{v});
		return this;
	}
	/**
	 * 生成自身sql语句
	 */
	public String toString(){
		String sql="";
		for (int i=0;i<list.size();i++) {
			sqlHandle sqlHandle = (sqlHandle) list.get(i);
			sql+=addWhereSql(sqlHandle.strSql,sqlHandle.fsql,sqlHandle.type);
		}
		return sql;
	}
}